using System;
using System.Collections.Generic;
using System.Text;

namespace Lizk.SimpleHUD
{
    public class HUD2dList : HUDContainerSimple
    {
        private float percentStretch = 0.50f;
        private SizeS minItemSize = new SizeS(140,140);
        SizeS currentItemSize;
        private int startRow = 0, selectedIndex = 0, currentRow = 0, rowAmount = 0, itemsPerRow =0;

        public event EventHandler<SelectionEventArgs> SelectedIndexChanged;

        public HUD2dList(SizeS itemSize)
        {
            this.minItemSize = itemSize;   
        }

        
        public SizeS ItemSize
        {
            get { return minItemSize; }
            set { minItemSize = value; }
        }


        public override void ResizeMove(RectangleS oldRect, RectangleS newRect)
        {
            base.ResizeMove(oldRect, newRect);
            MoveItems(true);
        }

        public int StartRow
        {
            get
            {
                return startRow;
            }
            set
            {
                if (startRow != value)
                {
                    int oldIndex = selectedIndex;
                    startRow = value;
                    MoveItems(true);
                    if (oldIndex != selectedIndex && SelectedIndexChanged != null)
                        SelectedIndexChanged(this, new SelectionEventArgs(oldIndex, true));
                }
            }
        }

        public void SetStartRow(int value, bool animate)
        {
            int oldIndex = selectedIndex;
            startRow = value;
            MoveItems(animate);
            if (oldIndex != selectedIndex && SelectedIndexChanged != null)
                SelectedIndexChanged(this, new SelectionEventArgs(oldIndex, true));
        }

        public int SelectedIndex
        {
            get
            {
                return selectedIndex;
            }
            set
            {
                if (selectedIndex != value)
                {
                    int old = selectedIndex;
                    selectedIndex = value;
                    MoveItems(true);

                    if (old != selectedIndex && SelectedIndexChanged != null)
                        SelectedIndexChanged(this, new SelectionEventArgs(old, true));
                }
            }
        }

        public T GetSelectedControl<T>() where T : HUDControl
        {
            return selectedIndex < controls.Count && selectedIndex >= 0 ? (T)controls[selectedIndex] : null;
        }

        public HUDControl SelectedControl
        {
            get { return controls[selectedIndex]; }
        }

        public void Add(HUDControl item, bool animate)
        {
            base.Add(item);
            MoveItems(animate);
        }


        public int SelectedRow
        {
            get
            {
                return currentRow;
            }
            set
            {
                if (currentRow != value)
                {
                    int newIndex = value * itemsPerRow + selectedIndex % itemsPerRow;
                    if(newIndex < 0)
                        return;
                    if (currentRow == (Count - 1) / itemsPerRow && newIndex >= Count)
                        return;
                    int old = selectedIndex;
                    selectedIndex = newIndex;
                    MoveItems(true);

                    if (old != selectedIndex && SelectedIndexChanged != null)
                        SelectedIndexChanged(this, new SelectionEventArgs(old, true));
                }
            }
        }

        public int SelectedColumn
        {
            get
            {
                return itemsPerRow > 0 ? selectedIndex % itemsPerRow : -1;
            }
            set
            {
                if (itemsPerRow == 0)
                    return;
                if (selectedIndex % itemsPerRow != value && value >= 0 && value < itemsPerRow)
                {
                    int oldIndex = selectedIndex;
                    selectedIndex = value % itemsPerRow + currentRow * itemsPerRow;
                    if(selectedIndex >= Count && currentRow > 0)
                        selectedIndex = value % itemsPerRow + (currentRow-1) * itemsPerRow;

                    MoveItems(true);
                    if (oldIndex != selectedIndex && SelectedIndexChanged != null)
                        SelectedIndexChanged(this, new SelectionEventArgs(oldIndex, true));


                }
            }
        }


        public void SetSelectedIndex(int value, bool animate)
        {
            int old = selectedIndex;
            selectedIndex = value;

            MoveItems(animate);
            if (old != selectedIndex && SelectedIndexChanged != null)
                SelectedIndexChanged(this, new SelectionEventArgs(old, true));

        }

        public RectangleS Selection
        {
            get { return itemsPerRow > 0 ? new RectangleS(new PointS((selectedIndex % itemsPerRow) * currentItemSize.Width, (currentRow - startRow) * currentItemSize.Height), currentItemSize) : RectangleS.Empty; }
        }


        public void MoveItems(bool animate) 
        {


            // Arranges all items into the grid.
            PointS offSet = new PointS();
            float rowMaxHeight = 0f;
            int itemsInThisRow = 0;

            itemsPerRow = (int)Math.Round(Bounds.Width / minItemSize.Width);
            if (itemsPerRow == 0)
                return;
            
            //float rest = Bounds.Width % (minItemSize.Width * percentStretch);
            
            currentItemSize = minItemSize;

            currentItemSize = new SizeS(Bounds.Width / itemsPerRow, currentItemSize.Height);


            // if selectedindex < 0 selectedindex = 0
            // if selectedindex >= controlcount  selectedindex = controlcount -1

            // if startindex is higher that the current row, set startindex = currentrow

            // if currentrow is higher than startindex + amount of shown rows, startindex = currentrow - amount of shown rows


            if (selectedIndex < 0) selectedIndex = 0;
            if (selectedIndex >= Count) selectedIndex = Count - 1;
            currentRow = selectedIndex / itemsPerRow;
            rowAmount = (int)(Bounds.Height / currentItemSize.Height);
            if (startRow > currentRow) startRow = currentRow;
            if (rowAmount-1 < currentRow - startRow) startRow = currentRow - rowAmount+1;
            




            offSet.Y = currentItemSize.Height * -startRow;

            for (int i = 0; i < this.Count; i++)
            {
                HUDControl control = this[i];
                // does it fit onto this row
                    // put it into the row
                // else
                    // are there no other items in this row
                        // squeeze it to fit an entire row
                    // else
                        // can wee squeeze it a little?
                            // squeeze all items a little to fit the last item
                        // else
                            // reset the offsetPointer and start a new row. Add the item there.

                if (rowMaxHeight < control.Bounds.Height)
                    rowMaxHeight = control.Bounds.Height;

                PointS newPosition;
                SizeS newSize = currentItemSize;
                if (offSet.X + currentItemSize.Width <= Bounds.Width)
                {
                    newPosition = new PointS(offSet.X, offSet.Y);
                    offSet.X += currentItemSize.Width;
                    itemsInThisRow++;
                }
                else
                {
                    /*if ((itemSize.Width + offSet.X) * percentStretch + Bounds.Width - offSet.X >= itemSize.Width)
                    {
                        // change the width of all items in this row, and update their positions.
                        float amountToChange = (itemSize.Width + offSet.X - Bounds.Width) / (float)(itemsInThisRow + 1f);
                        offSet.X = 0;
                        for (int j = i - itemsInThisRow; j < i; j++)
                        {
                            if (animate)
                            {
                                this[j].Destination = offSet;
                                this[j].DestinationSize = new SizeS(itemSize.Width - amountToChange, itemSize.Height);
                            }
                            else
                            {
                                this[j].Location = offSet;
                                this[j].Size = new SizeS(itemSize.Width - amountToChange, itemSize.Height);
                            }
                            offSet.X += itemSize.Width - amountToChange;
                        }
                        newPosition = new PointS(offSet.X, offSet.Y);
                        newSize = new SizeS(itemSize.Width - amountToChange, itemSize.Height);
                        offSet.X = 0;
                        offSet.Y += rowMaxHeight;
                        rowMaxHeight = 0;
                        itemsInThisRow = 0;
                    }
                    else*/
                    {
                        newSize = new SizeS(currentItemSize.Width, currentItemSize.Height);
                        newPosition = new PointS(offSet.X, offSet.Y);
                        offSet.X = 0;
                        offSet.Y += rowMaxHeight;
                        rowMaxHeight = 0;
                        if (itemsInThisRow != 0)
                        {
                            itemsInThisRow = 0;
                            i--;
                            continue;
                        }

                    }

                }
                if (animate)// && (RectangleS.Intersect(new RectangleS(newPosition, newSize), new RectangleS(PointS.Empty, Size)) != RectangleS.Empty || RectangleS.Intersect(control.Bounds, new RectangleS(PointS.Empty, Size)) != RectangleS.Empty))
                {
                    control.Destination = newPosition;
                    control.DestinationSize = newSize;
                }
                else
                {
                    control.Location = newPosition;
                    control.Size = newSize;
                }
            }

        
        
        }


    }
}
